#!/usr/bin/env python

import sys, os
from os3.utils.utils import md5crypt
from liwe.module import LiweModule

class User ( LiweModule ):
	def __init__ ( self, liwe ):
		super ( User, self ).__init__ ( liwe, "user" )
		self.group_on = self.cfg.get ( 'group_enabled', 1 )


	#=================================================
	# OVERRIDDABLE METHODS
	#=================================================
	def get_manip ( self, row ):
		pass

	def list_manip ( self, row ):
		row [ 'id'] = row [ 'uid' ]

		if not row.get ( 'last_log' ): row [ 'last_log' ] = ''
	
		row [ '_enabled' ] = 'NO'
		if row.get ( 'enabled' ): row [ '_enabled' ] = 'SI'

	def session_clean ( self ):
		if not int ( self.cfg.get ( 'check_unique', 0 ) ): return 
		self.dbm.delete ( "user_session", "DATE_ADD( lastlog, INTERVAL %s MINUTE ) < NOW()" % self.cfg.get ( "session.timeout", 30 ) )

	def session_exists ( self, uid, check_session ):
		if not int ( self.cfg.get ( 'check_unique', 0 ) ): return False
		if not check_session: return False

		vals = self.dbm.single_row ( "user_session", "uid", "uid = '%s'" % uid, debug = self.debug () )
		if vals: return True

		# Sessione gia' presente in DB
		return False

	def session_update ( self ):
		if not int ( self.cfg.get ( 'check_unique', 0 ) ): return
		self.dbm.update ( "user_session", { "lastlog" : "*NOW()" }, "session_id = '%s'" % self.liwe.pyhp.session.id )

	def session_start ( self, uid ):
		if not int ( self.cfg.get ( 'check_unique', 0 ) ): return
		try:
			self.dbm.insert ( "user_session", { "lastlog" : "*NOW()", "uid" : uid, "session_id" : self.liwe.pyhp.session.id } )
		except:
			pass

	def session_logout ( self ):
		if not int ( self.cfg.get ( 'check_unique', 0 ) ): return
		self.dbm.delete ( "user_session", "session_id = '%s'" % self.liwe.pyhp.session.id )

	def login_success ( self ):
		pass

	#=================================================
	# PUBLIC
	#=================================================
	def login ( self, login = '', pwd = '', email = '', check_session = True ):
		conds = []

		if login: conds.append ( "login = '%s'" % login )
		if email: conds.append ( "email = '%s'" % email )

		vals = self.dbm.single_row ( 'user_login', [ 'uid', 'login', 'passwd', 'email', 'check_session' ], ' AND '.join ( conds ), debug = self.debug () )

		if not vals:
			self.liwe.invoke ( "stats.ajax.log", "user", "0", "wrong-login" )
			self.liwe.err_code = 1
			self.liwe.err_descr = "Login o password errata"

			sys.stderr.write ( "user.login: ERRORE: login inesistente '%s (%s)'\n" % ( login, email ) )


			return 

		if vals [ 'passwd' ] != md5crypt ( pwd ):
			self.liwe.invoke ( "stats.ajax.log", "user", "0", "wrong-password" )
			self.liwe.err_code = 1
			self.liwe.err_descr = "Login o password errata"
			sys.stderr.write ( "user.login: ERRORE: password sbagliata '%s (%s)' - %s\n" % ( login, email, pwd ) )


			return 
	
		self.session_clean ()

		if check_session and self.session_exists  ( vals [ 'uid' ], vals [ 'check_session' ] ):
			self.liwe.invoke ( "stats.ajax.log", "user", vals [ 'uid' ], "session-exists" )
			self.liwe.err_code = 1
			self.liwe.err_descr = "Utente gia' collegato al sistema"
			sys.stderr.write ( "user.login: ERRORE: utente '%s' gia' collegato al sistema\n" % login )


			return

		self._set_session_data ( vals.get ( "uid", -1 ), vals.get ( "login", "no login" ), vals.get ( 'email', '' ) )

		vals [ 'group' ] = self.liwe.pyhp.session.data.get ( 'group' )	

		self.dbm.update ( "user_login", { 'last_log': '*NOW()' }, "uid = '%s'" % vals [ 'uid' ] )

		del vals [ 'passwd' ]
		
		if check_session:
			self.session_start ( vals [ 'uid' ] )

		self.liwe.invoke ( "stats.ajax.log", "user", vals [ 'uid' ], "login" )

		# Call the user-overrddibale `login_success'
		self.login_success ()
	
		return vals

	def _set_session_data ( self, uid, login, email ):
		self.liwe.pyhp.session.data [ 'uid' ] = uid
		self.liwe.pyhp.session.data [ 'login' ] = login
		self.liwe.pyhp.session.data [ 'email' ] = email

		gr = self.list_groups ( uid = uid )
		if gr:
			self.liwe.pyhp.session.data [ 'groups' ] = gr [ 'groups' ]
	
		

	def change_password ( self, new_pwd = '', email = '', token = '' ):
		#sys.stderr.write ( "\n\n -------------- change_password: new_pwd: %s, email: %s, token = %s\n\n" % ( new_pwd, email, token ) )
		if token and email:
			user_info = self.dbm.single_row ( "user_login", [ "uid", "login", "passwd", "email", "enabled" ], "email = '%s'" % email )
			chk = self.token ( user_info = user_info )	
			if chk != token: return
			uid = user_info [ 'uid' ]
		else:
			uid = self.liwe.pyhp.session.data.get ( "uid", -1 )
			if uid == -1:
				return

		dct = { "passwd" : md5crypt ( new_pwd ) }
		self.dbm.update ( "user_login", dct, "uid = '%s'" % uid, debug = self.debug () )
		#send email after password change
		user_info [ 'site_name' ] = self.liwe.cfg.get ( "site.name", "Sito Esempio" )
		user_info [ 'pwd' ] = new_pwd

		if int ( self.liwe.cfg.get ( "debug.enabled", 0 ) ) == 0:
			subject = self.templates [ 'mail-lostpwd-subj' ] % user_info
			mail_sender = self.liwe.email ( sender = self.cfg.get ( "site.email.sender", "noreply@example.com" ), subject = subject )
			mail_sender.to ( email )
			mail_sender.text ( self.templates [ 'mail-lostpwd' ] % user_info )
			mail_sender.html ( self.templates [ 'mail-lostpwd-html' ] % user_info )
			mail_sender.send ()

	def change_pwd ( self, uid, pwd ):
		dct = { "passwd" : md5crypt ( pwd ) }
		self.dbm.update ( "user_login", dct, "uid = '%s'" % uid )
	

	def lost_password ( self, email = '' ):
		if not email: return
		# Recupero lo uid in base all'indirizzo di email
		vals = self.dbm.single_row ( "user_login", [ "uid", "login", "passwd", "email", "enabled" ], "email = '%s'" % email )
		if not vals:
			self.liwe.err_code = 1
			self.liwe.err_descr = "Indirizzo email %s non presente nei nostri database" % email
			sys.stderr.write ( "user.lost_password: ERRORE: indirizzo email: '%s' inesistente\n" % email )
			return
		vals [ 'site_name' ] = self.liwe.cfg.get ( "site.name", "Sito Esempio" )
		vals [ 'token' ] = self.token ( user_info = vals )
		vals [ 'url_token' ] = os.path.join ( self.liwe.base_url, '?#__m=user,_page=change_password,token=%(token)s,email=%(email)s' % vals ) 
		if int ( self.liwe.cfg.get ( "debug.enabled", 0 ) ) == 0:
			subject = self.templates [ 'mail-lostpwd-subj' ] % vals
			mail_sender = self.liwe.email ( sender = self.liwe.cfg.get ( "site.email.sender", "noreply@example.com" ), subject = subject )
			mail_sender.to ( email )
			mail_sender.text ( self.templates [ 'mail-token' ] % vals )
			mail_sender.html ( self.templates [ 'mail-token-html' ] % vals )
			mail_sender.send()

	def remote_login ( self, service_name, email ):
		vals = self.dbm.single_row ( "user_login", [ "uid", "login" ], "email = '%s'" % email )
		# se non esiste lo creo apposta
		if not vals:
			dct = { "login" : email,
				"passwd" : service_name.upper (),
				"email" : email,
				"enabled" : 1,
				"created" : "*NOW()" }

			self.dbm.insert ( "user_login", dct )
			vals = {}
			vals [ "uid" ] = self.dbm.insert_id ()
			vals [ "login" ] = email

		self._set_session_data ( vals.get ( "uid", -1 ), vals.get ( "login", "no login" ) )

		self.dbm.update ( "user_login", { 'last_log': '*NOW()' }, "uid = '%s'" % vals [ 'uid' ] )

		return "OK"

	def logout ( self ):
		self.liwe.invoke ( "stats.ajax.log", "user", self.liwe.pyhp.session.data.get ( 'uid', 0 ), "logout" )
		self.session_logout ()
		self.liwe.pyhp.session.delete ()

	def list ( self ):
		vals = self.dbm.all_rows ( "user_login", [ "uid", "login", "email", "created", "last_log", "enabled" ], extras = "ORDER BY login" )
		return vals

	def list_new ( self, email = '', enabled = 1, login = '', created = None, last_log = None, start_pos = 0, limit = 10 ):
		extras = " ORDER BY u.login LIMIT %s,%s " % ( start_pos, limit )

		tables = [ "user_login AS u" ]
		fields = [ "u.uid", "u.login", "u.email", "u.created", "u.last_log", "u.enabled" ]

		conds = []
		if login: conds.append ( "u.login LIKE '%%%s%%'" % login )  
		if email: conds.append ( "u.email LIKE '%%%s%%'" % email )  
		#if created: conds.append ( "u.created = '%s'" % created )  
		#if last_log: conds.append ( "u.last_log = '%s'" % last_log )  
		if enabled != 1: conds.append ( "u.enabled = '%s'" % enabled )  

		tot_rows = self.dbm.count ( tables, fields, conds = " AND ".join ( conds ) )

		cur = self.dbm.select ( tables, fields, conds = " AND ".join ( conds ), extras = extras )

		users = []

		if cur:
			for u in cur:
				self.list_manip ( u )
				users.append ( u )

			cur.close ()

		return { "rows" : users, "tot_rows" : tot_rows }

	def get_info ( self, uid, group = '' ):
		# FIXME: controllare i permessi e usare la uid solo se puo' gestire gli utenti
		#uid = self.liwe.pyhp.session.data.get ( "uid", 0 )
		

		tables = [ 'user_login AS u' ]
		fields = [ 'u.uid', 'u.login', 'u.email', 'u.created', 'u.last_log', 'u.enabled' ]
		conds  = [ "u.uid = '%s'" % uid ]
		extras = []

		vals = self.dbm.single_row ( tables, fields , ' AND '.join ( conds ) )

		if vals:
			vals [ 'groups' ] = []

			if self.group_on and group:
				groups = self.list_groups ( gid = 0, name = '', descr = '' , login = '', uid = uid, start_point = 0, limit = 10 )
				if groups:
					vals [ 'groups' ] = groups

		return vals

		#previous version
		"""
		vals = self.dbm.single_row ( 'user_login', [ 'uid', 'login', 'email', 'created', 'last_log', 'enabled' ], "uid = '%s'" % uid )
		return vals
		"""
	def token ( self, email = '', user_info = {} ):
		#NOTE: token will last only for the current date
		from datetime import date
		if not user_info:
			user_info = self.dbm.single_row ( "user_login", [ "uid", "login", "passwd", "email", "enabled" ], "email = '%s'" % email )

		if not user_info: return
	
		token = md5crypt ( str ( user_info.get ( 'uid' ) ) + str ( date.today () ) + str ( user_info.get ( 'created' ) ) + str ( user_info.get ( 'email' ) ) )
		return token	

	def create ( self, login, passwd, email, enabled = 1, uid = -1 ):
		site_name = self.liwe.cfg.get ( "site.name", "Sito Esempio" )
		
		db_check = self.login_exists ( login = login, email = email, uid = uid )
		if db_check:
			self.liwe.set_error ( '42', "Login o email gia' esistenti" )
			return

		dct = { "login" : login,
			#"passwd" : md5crypt ( passwd ),
			"email" : email,
			"enabled" : enabled,
			"created" : "*NOW()" }

		if passwd : dct [ 'passwd' ] = md5crypt ( passwd )

		new_uid = uid

		if uid == -1:
			self.dbm.insert ( "user_login", dct, debug = self.debug() )
			new_uid = self.dbm.insert_id ()

			dct [ 'site_name' ] = site_name 
			dct [ 'passwd' ] = passwd

			if int ( self.liwe.cfg.get ( "debug.enabled", 0 ) ) == 0:
				
				sender = self.cfg.get ( "site.email.sender", "noreply@example.com" )
				subject = self.templates [ 'mail-newuser-subject' ] % dct
				mail_sender = self.liwe.email ( sender, subject )
				mail_sender.to ( email )
				mail_sender.text ( self.templates [ 'mail-newuser' ] % dct )
				mail_sender.html ( self.templates [ 'mail-newuser-html' ] % dct )			
				mail_sender.send()

				subject = self.templates [ 'mail-newuser-adv-subj' ] % dct
				mail_sender = self.liwe.email ( sender, subject )
				mail_sender.to ( self.cfg.get ( "site.email.notify", "info@example.com" ) )
				mail_sender.text ( self.templates [ 'mail-newuser-adv' ] % dct )
				mail_sender.html ( self.templates [ 'mail-newuser-adv-html' ] % dct )
				mail_sender.send()

		else:
			self.dbm.update ( "user_login", dct, "uid = %s" % uid )

		if self.liwe.pyhp.session.data.get ( "uid", -1 ) == -1:
			self._set_session_data ( new_uid, dct.get ( "login" ), dct.get ( "email", "" ) )
			# Call the user-overrddibale `login_success'
			self.login_success ()

		return new_uid

	
	def modify ( self, login, email, oldpwd, pwd ):
		uid = self.liwe.pyhp.session.data.get ( "uid", -1 )
		if uid == 1 :
			self.liwe.set_error ( '1', "Utente non loggato" )
			return
		user = self.dbm.single_row ( 'user_login', [ 'uid', 'login', 'email', 'created', 'last_log', 'enabled', 'passwd' ], "uid = '%s'" % uid )
		if not user :
			self.live.set_error ( '2', "Utente non valido" )
		
		#CHECK OLD PWD	
		if user [ 'passwd' ] != md5crypt ( oldpwd ):
			self.liwe.set_error ( '3', "Password errata" )
			return

		vals = {}
		#email_exist
		if self.login_exists ( login = user [ 'login' ], email = email, uid = uid ):
			self.liwe.set_error ( '4', "email gia presente" )
			return
		#login_exist
		if self.login_exists ( login = login, email = user [ 'email' ], uid = uid ):
			self.liwe.set_error ( '5', "None utente gia presente" )
			return

		vals [ 'email' ] = email
		vals [ 'login' ] = login

		if pwd : vals [ 'passwd' ] = md5crypt ( pwd )

		self.dbm.update ( "user_login", vals, "uid =%s" % uid )

		
		return vals	

	def login_exists ( self, login = '', email = '', uid = -1 ):
		"""
		Check if login / email exists in database
		"""
		conds = []

			

		if login: conds.append ( " login = '%s' " % login )
		if email: conds.append ( " email = '%s' " % email )

		where = " OR ".join ( conds ) 
		if uid != -1:
			where = "UID <> %s and ( %s )" % ( uid, where )

			
		vals = self.dbm.single_row ( "user_login", "uid", where, debug = self.debug() )

		if vals: 
			return True

		return False

	def update ( self, uid, login = '', passwd = '', email = '', enabled = -1 ):
		# FIXME: controllare i permessi e usare la uid solo se puo' gestire gli utenti
		#uid = self.liwe.pyhp.session.data.get ( "uid", 0 )

		return self.create ( login = login, passwd = passwd, email = email, enabled = enabled, uid = uid )

	def delete ( self, uids ):
		# FIXME: controllare i permessi e usare la uid solo se puo' gestire gli utenti
		#uid = self.liwe.pyhp.session.data.get ( "uid", 0 )
		uids = uids.split ( "|" )
		str_uids = " ,".join ( uids )
		

		self.dbm.delete ( "user_login", "uid IN ( %s )" % str_uids )

	def set_enabled ( self, uids, enabled = 0 ):
		# FIXME: controllare i permessi e usare la uid solo se puo' gestire gli utenti
		#uid = self.liwe.pyhp.session.data.get ( "uid", 0 )
		uids = uids.split ( "|" )
		str_uids = " ,".join ( uids )
		

		self.dbm.update ( "user_login", { 'enabled': enabled }, "uid IN ( %s )" % str_uids )

	###################################################################################################################
	# GROUP METHODS 
	###################################################################################################################

	def list_groups ( self, gid = 0, name = '', descr = '' , login = '', uid = -1, start_point = 0, limit = 10, full = '' ):

		extras = []
		extras.append ( ' ORDER BY g.name' )
		tables = [ "user_group AS g" ]
		fields = [ "g.gid", "g.name", "g.descr" ] 
		conds = ""

		if uid > 0:
			tables.append ( "user_u2g AS u" )
			conds = "g.gid = u.gid AND u.uid = %s" % uid 
			
		if uid < 0:
			extras.append ( " LIMIT %s,%s " % ( start_point, limit ) )

		tot_rows = self.dbm.count ( tables, fields, conds )

		cur = self.dbm.select ( tables, fields, conds, extras = ' '.join ( extras ) )

		groups = []

		if cur:
			for u in cur:
				if full: 
					res_perms = self.liwe.invoke ( "system.ajax.module_get_all_perms", "", u [ 'gid' ], "group" )
					u.update ( { 'perms' : res_perms [ 'perms' ] } )

				groups.append ( u )

			cur.close ()

		return { "rows" : groups, "tot_rows" : tot_rows, "groups" : groups }

	def create_group ( self, gid = 0, name = '', descr = '' ):

		dct = { 'name' : name , 'descr' : descr }
			
		if not gid:
			self.dbm.insert ( 'user_group', dct )
			last_gid = self.dbm.insert_id ()

			return last_gid

		self.dbm.update ( 'user_group', dct, "gid = '%s' " % gid )
		return

	def get_user_group ( self, uid = 0 ):
		#restituisce i gruppi assegnati ad un utente e quelli non assegnati
		fields = [ 'gid', 'name', 'descr' ] 

		conds = "gid in ( SELECT u2.gid from  user_u2g u2 join user_group ug on u2.gid=ug.gid  where u2.uid=%s )" % uid
		ingroup = self.dbm.all_rows ( "user_group", fields, conds, debug = self.debug () )

		conds = "gid not in ( SELECT u2.gid from  user_u2g u2 join user_group ug on u2.gid=ug.gid  where u2.uid=%s )" % uid
		notingroup = self.dbm.all_rows ( "user_group", fields, conds, debug = self.debug () )
	
		return { 'ingroup' : ingroup , 'notingroup' : notingroup }

		#select * from user_group where gid not in ( SELECT u2.gid from  user_u2g u2 join user_group ug on u2.gid=ug.gid  where u2.uid=2 )	
	
	def get_group_user ( self, gid = 0, not_in_group = '', uid = 0, login = '', email = '' ):

		if not gid: return []

		tables = [ "user_login AS u", "user_u2g AS ug" ]
		fields = [ "u.uid", "u.login", "u.email", "u.enabled" ]
		conds = []
		f_conds = []
		conds.append ( "u.uid = ug.uid" )
		conds.append ( "ug.gid = '%s'" % gid )
		extras = [ "ORDER BY u.login" ]

		if uid:
			f_conds.append ( "u.uid = %s" % uid )
		if login:
			f_conds.append ( "u.login LIKE '%%%s%%'" % login )
		if email:
			f_conds.append ( "u.email = '%s'" % email )

		#conds = conds + f_conds
		vals = self.dbm.all_rows ( tables, fields, ' AND '.join ( conds ), extras = ' '.join ( extras ), debug = self.debug () )

		if not vals: vals = []

		if not_in_group: 
			conds = []
			ids = [ "'%s'" % x [ 'uid' ] for x in vals ] 
			tables = [ "user_login AS u" ]
			if ids: conds.append ( "u.uid NOT IN ( %s )" % ','.join ( ids ) )
			conds = conds + f_conds
			vals = self.dbm.all_rows ( tables, fields, ' AND '.join ( conds ), extras = ' '.join ( extras ), debug = self.debug () )

			if not vals: vals = []

		return vals

	def get_group_range ( self, gid = "", uid = 0, login = '', email = '', flat = 0 ):
		if not gid: return []

		tables = [ "user_login AS u", "user_u2g AS ug" ]
		fields = [ "u.uid", "u.login", "u.email", "u.enabled", "ug.gid" ]
		conds = []
		f_conds = []
		conds.append ( "u.uid = ug.uid" )
		gids = gid.split ( '|' )
		#check gid: they all must be int
		try:
			[ int ( g ) for g in gids ]
		except:
			self.liwe.set_error ( '48', "gid must be an integer" )
			return

		if len ( gids ) > 1:
			j = "'" + "','".join ( gids ) + "'"
			conds.append ( "ug.gid IN( '%s' )" % "','".join ( gids ) )
		else:
			conds.append ( "ug.gid = '%s'" % gid )

		extras = [ "ORDER BY u.login" ]

		if uid:
			f_conds.append ( "u.uid = %s" % uid )
		if login:
			f_conds.append ( "u.login LIKE '%%%s%%'" % login )
		if email:
			f_conds.append ( "u.email = '%s'" % email )

		#conds = conds + f_conds
		vals = self.dbm.all_rows ( tables, fields, ' AND '.join ( conds ), extras = ' '.join ( extras ), debug = self.debug () )

		if not vals: vals = []
		if flat:
			return vals;
		group = {}
		for r in vals:
			tmp = group.get ( r [ 'gid' ], [] )
			tmp.append ( r )
			group [ r [ 'gid' ] ] = tmp
		return group

	def save_group_user ( self, gid = 0, ids = '' ):
		
		if not gid or not ids: return

		self.dbm.delete ( "user_u2g", "gid = '%s'" % gid )	
		for uid in ids.split ( '|' ):
			self.dbm.insert ( "user_u2g", { 'uid' : uid, 'gid' : gid } )


	def save_user_group ( self, uid = 0, gids = '' ):
		
		if not uid or not gids: return

		self.dbm.delete ( "user_u2g", "uid = '%s'" % uid )	
		for gid in gids.split ( '|' ):
			self.dbm.insert ( "user_u2g", { 'uid' : uid, 'gid' : gid } )

		
	def empty_group_user ( self, gid = 0, mode = "group" ):
		
		if not gid: return
		
		conds = "gid = %s" % gid
		if ( mode == "user" ):
			conds = "uid = %s" % gid
		self.dbm.delete ( "user_u2g", conds, debug = self.debug () )

	def delete_group ( self, ids ):
		
		ids_lst = ids.split ( '|' )
		for id_group in ids_lst:
			self.empty_group_user ( id_group )
			self.dbm.delete ( 'user_group', 'gid = %s' % id_group )

	def get_group ( self, gid = 0, users = 0 ):

		if not gid: return []

		tables = [ 'user_group AS g' ]
		fields = [ 'g.gid', 'g.name', 'g.descr' ] 
		conds  = [ "g.gid = '%s'" % gid ]
		extras = []

		vals = self.dbm.single_row ( tables, fields , ' AND '.join ( conds ) )

		if not vals: return []

		if vals and users:
			vals [ 'users' ] = self.get_group_user ( gid = gid, not_in_group = '' )

		return vals

		"""
		vals = self.dbm.single_row ( 'user_group', [ 'gid', 'name', 'descr' ], "gid = '%s'" % gid )
		return vals
		"""

	###################################################################################################################
	# ADMIN SESSION METHODS 
	###################################################################################################################

	def list_user_session ( self, uid = 0, email ='', login = '',  quant = 10, start_point = 0, do_count = 0 ):
		fields = [ 'session_id', 'uid', 'login', 'email', 'lastlog' ]
		conds = []
		conds.append ( "uid > 1" );
		if login: conds.append ( "login LIKE '%%%s%%'" % login )  
		if email: conds.append ( "email LIKE '%%%s%%'" % email )  
		if uid: conds.append ( "uid = %s" % uid )  
	
		extras = ''
		tot_rows = self.dbm.count ( 'list_user_session', 'uid', ' AND '.join ( conds ) )
		if do_count:
			extras = " LIMIT %s,%s" % ( start_point, quant )
		resp = self.dbm.all_rows ( 'list_user_session', fields , ' AND '.join ( conds ), extras = extras )
		if not resp:
			resp = []
		return { "rows" : resp, "tot_rows" : tot_rows }

	def del_user_session ( self, ids = "" ):
		ids = ids.split ( "|" )
		str_ids = " ,".join ( [ "'%s'" % x for x in ids ] )
		self.dbm.delete ( "user_session", "session_id IN ( %s )" % str_ids )

	###################################################################################################################
	# USER DATA METHODS
	###################################################################################################################
	def user_data_type_list ( self ):
		"""
		user_data_type_list () -> [ { "id_data_type", "name" } ]

		Lists all defined data types. 
		Returns a list of dictionaries, or empty list if not data_type defined.
		"""
		rows = self.dbm.all_rows ( "user_data_type", [ 'id_data_type', 'name' ], extras = "ORDER BY name", safe = True )
		return rows

	def user_data_type_set ( self, name, id_data_type = 0 ):
		"""
		user_data_type_set ( self, name, id_data_type = 0 )  -> id_data_type

		Creates / updates a new data_type.
		If ``id_data_type`` is defined, it is used for the update

		Returns the new ``id_data_type``
		"""

		dct = { "id_data_type" : id_data_type, "name" : name }
		self.dbm.replace ( "user_data_type", dct )

		return self.dbm.insert_id ()

	def user_data_type_get ( self, id_data_type = 0, name = '' ):
		"""
		user_data_type_get ( self, id_data_type = 0, name = '' ) -> { "id_data_type", "name" } 

		Search for a data_type. You can search for ``id_data_type`` or ``name`` (or both ... )

		Returns a dictionary with ``{ "id_data_type", "name" }`` or an empty dict if missing
		"""
		conds = []

		if id_data_type: conds.append ( "id_data_type = '%s'" % id_data_type )
		if name: conds.append ( "name = '%s'" % name )

		return self.dbm.single_row ( "user_data_type", [ "id_data_type", "name" ], ' AND '.join ( conds ), safe = True )

	def user_data_get ( self, uid, id_data_type = 0 ):
		"""
		user_data_get ( uid, id_data_type = 0 ) -> [ { "id_user_data", "id_data_type", "data", "name" } ]

		Search for all ``user_data`` defined for the given ``uid`` and (optionally) ``id_data_type``.
		Returns a list of dictionaries containing:
		
			- ``id_user_data``: the row ID
			- ``id_data_type``: the data_type id
			- ``data``:         the row value
			- ``name``: name of the data_type (as defined in ``user_data_type``)
		"""

		tables = [ "user_data AS ud", "user_data_type AS udt" ]
		fields = [ "ud.id_user_data", "ud.id_data_type", "ud.data", "udt.name" ]

		conds = [ "ud.uid = '%s'" % uid, "ud.id_data_type = udt.id_data_type" ]
		if id_data_type: conds.append ( "ud.id_data_type = '%s'" % id_data_type )

		return self.dbm.all_rows ( tables, fields, ' AND '.join ( conds ), safe = True )

	def user_data_set ( self, uid, id_data_type, value, id_user_data = 0 ):
		"""
		user_data_set ( self, uid, id_data_type, value, id_user_data = 0 )  -> id_user_data

		Creates / updates a new user_data.
		If ``id_user_data`` is defined, it is used for the update

		Returns the new ``id_user_data``
		"""
		dct = { "uid" : uid, "id_data_type" : id_data_type, "data" : value, "id_user_data" : id_user_data }

		self.dbm.replace ( "user_data", dct, debug = self.debug () )
		return self.dbm.insert_id ()
		
	def user_data_del ( self, uid = 0, id_user_data = 0 ):
		
		if not id_user_data : return
		conds = [ "id_user_data = %s" % id_user_data ]
		if uid:
			conds.append ( "uid = %s" % uid )

		self.dbm.delete ( "user_data", " AND ".join ( conds ) )

	def user_data_type_del ( self, id_data_type = 0 ):
		
		if not id_data_type : return
		self.dbm.delete ( "user_data_type", "id_data_type = %s" % id_data_type )
